package com.karaoke.android.data

import com.apkfuns.logutils.LogUtils
import com.karaoke.android.data.domain.DataDictionary
import com.karaoke.android.data.krealmextensions.queryFirst
import com.karaoke.android.data.krealmextensions.saveAll
import com.karaoke.android.data.service.DictionaryService
import com.karaoke.android.data.service.RoomService
import com.karaoke.android.data.service.SingerService
import com.karaoke.android.data.service.SongService
import com.karaoke.android.data.udp.UDPClient
import com.karaoke.android.data.websocket.WebSocketClient
import io.realm.Realm
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import retrofit2.converter.fastjson.FastJsonConverterFactory
import rx.Observable
import rx.Subscriber
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import java.net.UnknownHostException
import java.util.concurrent.TimeUnit

/**
 * Created by Administrator on 2017/4/11.
 */
object NetworkTools
{
    val serverAddress = "main.oksrv.com"


    val okhttpClient: OkHttpClient by lazy {
        OkHttpClient().newBuilder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).build()
    }

    val retrofit: Retrofit by lazy {
        Retrofit.Builder().client(okhttpClient)
                .baseUrl("http://$serverAddress")
                .addConverterFactory(FastJsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build()
    }


    val webSocketClient by lazy { WebSocketClient(serverAddress) }

    val udpClient by lazy { UDPClient(serverAddress) }

    val roomService: RoomService by lazy { retrofit.create(RoomService::class.java) }

    val singerService: SingerService by lazy { retrofit.create(SingerService::class.java) }

    val songService by lazy { retrofit.create(SongService::class.java) }

    val dictionaryService by lazy { retrofit.create(DictionaryService::class.java) }


    fun getLanguages(): Observable<List<DataDictionary>>
    {
        return getDictByPid(23).map {
            it.add(0, DataDictionary().apply {
                id = 0
                name = "全部"
                image = "{language-all}"
            })
            it
        }
    }

    fun getSingerAreas(): Observable<List<DataDictionary>>
    {
        return getDictByPid(22).map {
            it.add(0, DataDictionary().apply {
                id = 0
                name = "全部"
                image = "{singer-area-all}"
            })
            it
        }
    }

    fun getDictByPid(pId: Int): Observable<MutableList<DataDictionary>>
    {
        return Realm.getDefaultInstance().where(DataDictionary::class.java)
                .equalTo("parentId", pId)
                .findAll()
                .asObservable()
                .filter { it.isLoaded }
                .flatMap {
                    if (it.isNotEmpty())
                        Observable.just(Realm.getDefaultInstance().copyFromRealm(it))
                    else
                        NetworkTools.dictionaryService.dictionaryByPid(pId).onIO().map { it.saveAll();it }
                }
    }

    fun getDictionary(id: Int): Observable<DataDictionary>
    {
        val item = DataDictionary().queryFirst { it.equalTo("id", id) }
        if (item == null)
        {
            return NetworkTools.dictionaryService.getOne(id).onIO()
        }
        else
        {
            return Observable.just(item)
        }
    }
}

fun <T> Observable<T>.onUI(): Observable<T>
{
    return observeOn(AndroidSchedulers.mainThread())
}

fun <T> Observable<T>.onUI(onNext: (T) -> Unit): Subscription
{
    return observeOn(AndroidSchedulers.mainThread()).subscribe(onNext)
}

fun <T> Observable<T>.onUI(onNext: (T) -> Unit, onError: (Throwable) -> Unit): Subscription
{
    return observeOn(AndroidSchedulers.mainThread()).subscribe(onNext, onError)
}

fun <T> Observable<T>.onUI(subscriber: Subscriber<T>): Subscription
{
    return observeOn(AndroidSchedulers.mainThread()).subscribe(subscriber)
}

fun <T> Observable<T>.onIO(): Observable<T>
{
    return subscribeOn(Schedulers.io())
}